package com.devilvan.betrice.brand.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devilvan.betrice.annotation.BetriceRunTime;
import com.devilvan.betrice.brand.po.CnBrandPo;
import com.devilvan.betrice.brand.service.CnBrandService;
import com.devilvan.betrice.brand.mapper.CnBrandMapper;
import com.devilvan.betrice.brand.repository.CnBrandRepository;
import com.devilvan.betrice.brand.vo.CnBrandVo;
import com.devilvan.betrice.common.BetriceResultVo;
import com.devilvan.betrice.common.BetriceResultCode;
import com.devilvan.betrice.brand.constant.CnBrandConstant;
import com.devilvan.betrice.brand.constant.CnBrandRedisConstant;
import com.devilvan.betrice.component.BetriceSnapComponenet;
import com.devilvan.betrice.dto.BetriceSnapDto;
import com.devilvan.betrice.exception.BetriceException;
import com.devilvan.betrice.request.BetriceHttpBuilder;
import com.devilvan.betrice.request.pojo.BetriceHttpClient;
import com.devilvan.betrice.request.component.HttpClientComponent;
import com.devilvan.betrice.request.component.JsoupComponent;
import com.devilvan.betrice.util.UCopy;
import com.devilvan.betrice.util.ExploreDriverUtil;
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @author Evad.Wu
 * @Description 中国品牌网 业务逻辑类
 * @date 2022-09-16
 */
@Service
public class CnBrandServiceImpl extends ServiceImpl<CnBrandMapper, CnBrandPo> implements CnBrandService {
    private ChromeDriver chromeDriver;

    @Resource(name = "jsoupComponent")
    private JsoupComponent jsoupComponent;
    @Resource(name = "betriceSnapComponenet")
    private BetriceSnapComponenet betriceSnapComponenet;
    @Resource(name = "httpClientComponent")
    private HttpClientComponent httpClientComponent;
    @Resource(name = "betriceRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;
    @Resource(name = "cnBrandRepository")
    private CnBrandRepository cnBrandRepository;

    @Override
    public List<CnBrandVo> doJsoupCrawler(String url) {
        List<CnBrandVo> cnBrandVoList = new ArrayList<>();
        Element body = jsoupComponent.getBody(url);
        Elements elements = body.select("div.TTclas_tit>a,div.TTclas_ims_tit>p>a,ul[class='TTclas_ims_list clearfix']>li>a");
        for (Element element : elements) {
            String industryUrl = CnBrandConstant.BRAND_PREFFIX + element.attr("href");
            String title = element.attr("title");
            CnBrandVo cnBrandVo = new CnBrandVo(industryUrl, title);
            cnBrandVoList.add(cnBrandVo);
        }
        return Optional.of(cnBrandVoList).filter(f -> f.size() > 0)
                .orElseThrow(() -> new BetriceException("采集数据为空！"));
    }

    @Override
    public List<CnBrandVo> doCrawlViewSource() {
        List<CnBrandVo> cnBrandVoList = new ArrayList<>();
        try {
            Element body = Jsoup.parse(new File(CnBrandConstant.BRAND_VIEW_SOURCE), "UTF-8").body();
            Elements elements = body.select("div.TTclas_tit>a,div.TTclas_ims_tit>p>a,ul[class='TTclas_ims_list clearfix']>li>a");
            for (Element element : elements) {
                String industryUrl = CnBrandConstant.BRAND_PREFFIX + element.attr("href");
                String title = element.attr("title");
                CnBrandVo cnBrandVo = new CnBrandVo(industryUrl, title);
                cnBrandVoList.add(cnBrandVo);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Optional.of(cnBrandVoList).filter(f -> f.size() > 0)
                .orElseThrow(() -> new BetriceException("采集数据为空！"));
    }

    @Override
    @BetriceRunTime
    @Async(value = "threadPoolExecutor")
    public CompletableFuture<BetriceResultVo<CnBrandPo>> doCnBrand() {
        String snapBrandUrl = Optional.ofNullable(redisTemplate.opsForList().leftPop(CnBrandRedisConstant.KEY_SNAP_BRAND_URL))
                .map(Object::toString)
                .orElseThrow(() -> new BetriceException(CnBrandRedisConstant.KEY_SNAP_BRAND_URL + "队列已空！"));
        return CompletableFuture.completedFuture(this.doCnBrandHandler(snapBrandUrl));
    }

    @Override
    public BetriceResultVo<CnBrandPo> doCnBrandException() {
        String snapBrandUrl = Optional.ofNullable(redisTemplate.opsForList().leftPop(CnBrandRedisConstant.KEY_SNAP_EXCEPTION_URL))
                .map(Object::toString)
                .orElseThrow(() -> new BetriceException(CnBrandRedisConstant.KEY_SNAP_EXCEPTION_URL + "队列已空！"));
        return this.doCnBrandHandler(snapBrandUrl);
    }

    private BetriceResultVo<CnBrandPo> doCnBrandHandler(String snapBrandUrl) {
        BetriceResultVo<CnBrandPo> betriceResultVo = new BetriceResultVo<>();
        chromeDriver = Optional.ofNullable(chromeDriver).orElseGet(ExploreDriverUtil::getChromeDriver);
        try {
            String[] split = snapBrandUrl.split(",");
            String industryUrl = split[0];
            String industryName = split[1];
            Elements ulList = jsoupComponent.getJsoupConnection(industryUrl).get().select("div.rank_title_box > ul > li");
            //获取要截图的地址，注：需要先获取地址哦，不然下方获取的宽度高度就会是弹窗的高和宽，而不是页面内容的高宽
            chromeDriver.get(industryUrl);
            BetriceSnapDto betriceSnapDto = new BetriceSnapDto(
                    0L, 260L, 1228L, 2150L,
                    "D:\\Mine\\杂物\\中国品牌1\\" + industryName + "\\" + industryName + "十大品牌品牌榜.png");
            String json;
            String response;
            String dataFid = null;
            for (Element li : ulList) {
                if (dataFid == null) {
                    dataFid = li.attr("data-fid");
                }
                String dataVotetype = li.attr("data-votetype");
                if ("shida".equals(dataVotetype)) {
                    // 1. 品牌榜
                    betriceSnapComponenet.snapScreen(betriceSnapDto);
                } else if ("favor".equals(dataVotetype)) {
                    // 2. 优选榜
                    json = "{\"fid\" : " + dataFid + ", \"votetype\" : \"favor\"}";
                    BetriceHttpClient betriceHttpClient = BetriceHttpBuilder.create()
                            .setHttpRequest(RequestMethod.POST, "https://www.chinapp.com/paihang/getList", json)
                            .build();
                    response = httpClientComponent.doExecute(betriceHttpClient);
                    Integer code = JSON.parseObject(response).getInteger("code");
                    if (400 != code) {
                        chromeDriver.findElement(By.cssSelector(li.cssSelector())).click();
                        betriceSnapDto.setExportPath("D:\\Mine\\杂物\\中国品牌1\\" + industryName + "\\" + industryName + "十大品牌优选榜.png");
                        TimeUnit.MILLISECONDS.sleep(2000);
                        betriceSnapComponenet.snapScreen(betriceSnapDto);
                    }
                } else if ("acute".equals(dataVotetype)) {
                    // 3. 新锐榜
                    json = "{\"fid\" : " + dataFid + ", \"votetype\" : \"acute\"}";
                    BetriceHttpClient betriceHttpClient = BetriceHttpBuilder.create()
                            .setHttpRequest(RequestMethod.POST, "https://www.chinapp.com/paihang/getList", json)
                            .build();
                    response = httpClientComponent.doExecute(betriceHttpClient);
                    Integer code = JSON.parseObject(response).getInteger("code");
                    if (400 != code) {
                        chromeDriver.findElement(By.cssSelector(li.cssSelector())).click();
                        betriceSnapDto.setExportPath("D:\\Mine\\杂物\\中国品牌1\\" + industryName + "\\" + industryName + "十大品牌新锐榜.png");
                        TimeUnit.MILLISECONDS.sleep(2000);
                        betriceSnapComponenet.snapScreen(betriceSnapDto);
                    }
                } else if ("famous".equals(dataVotetype)) {
                    // 4. 人气榜
                    chromeDriver.findElement(By.cssSelector(li.cssSelector())).click();
                    betriceSnapDto.setExportPath("D:\\Mine\\杂物\\中国品牌1\\" + industryName + "\\" + industryName + "十大品牌人气榜.png");
                    TimeUnit.MILLISECONDS.sleep(2000);
                    betriceSnapComponenet.snapScreen(betriceSnapDto);
                }
            }
            betriceResultVo.setSuccess(true);
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "截图成功：" + snapBrandUrl);
        } catch (HttpStatusException e) {
            log.error("网页异常：" + e);
        } catch (Exception e) {
            e.printStackTrace();
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "操作失败：" + snapBrandUrl + "\n" + e);
            redisTemplate.opsForList().leftPush(CnBrandRedisConstant.KEY_SNAP_EXCEPTION_URL, snapBrandUrl);
        }

        return betriceResultVo;
    }

    @Override
    public BetriceResultVo<CnBrandPo> saveCnBrandBatch(List<CnBrandVo> cnBrandVoList) {
        BetriceResultVo<CnBrandPo> betriceResultVo = new BetriceResultVo<>();
        List<CnBrandPo> cnBrandPoList = UCopy.fullCopyCollections(cnBrandVoList, CnBrandPo.class);
        try {
            this.saveUpdateBatch(cnBrandPoList);
            betriceResultVo.setSuccess(true);
            betriceResultVo.setHandleCount(cnBrandPoList.size());
            betriceResultVo.result(BetriceResultCode.SUCCESS_200.getCode(), "操作成功！");
        } catch (Exception e) {
            e.printStackTrace();
            betriceResultVo.result(BetriceResultCode.FAILED_500.getCode(), "操作失败：" + e);
        }
        return betriceResultVo;
    }

    @Override
    public CnBrandPo saveUpdate(CnBrandPo cnBrandPo) {
        return cnBrandRepository.saveAndFlush(cnBrandPo);
    }

    @Override
    public List<CnBrandPo> saveUpdateBatch(List<CnBrandPo> list) {
        return cnBrandRepository.saveAllAndFlush(list);
    }

    @Override
    public List<CnBrandPo> findAllIndustryUrlName() {
        LambdaQueryWrapper<CnBrandPo> queryWrapper = new QueryWrapper<CnBrandPo>().lambda();
        queryWrapper.select(CnBrandPo::getIndustryUrl, CnBrandPo::getIndustryName);
        return this.list(queryWrapper);
    }

}
